Category Theory for Programmers 9
Chapter 9, Function Types
我们之前已经见识过,在 Set 范畴中,对象
使用泛构造的方式定义函数类型:一个函数类型
(由于
形式化地,函数对象是
泛构造在
Set 只是众多笛卡尔闭范畴(Cartesian Closed Categories)的一个例子。一个笛卡尔闭范畴必须满足:
- 终对象;
- 任意一对对象的积;
- 任意一对对象的指数(函数类型)。
笛卡尔闭范畴为简单类型 lambda 演算提供了基础。如果笛卡尔闭范畴还满足初始对象和余积,同时积能够对余积分配,那么它就被称为双笛卡尔闭范畴(Bicartesian Closed Categories)。Set 就是双笛卡尔闭范畴。
数学文献中,函数对象,也就是
从初始对象到任意类型的态射只有一个,也就是一个单元素集合,正是 Set 的终止对象。在 Haskell 中这就对应 absurd 函数。 从任何对象到终对象的态射只有一个。一般地,从 a 到终对象的内部 hom 对象,同构于终对象本身。在 Haskell 中从任意类型 a 到 unit 只有一个函数 unit。 从终对象出发到对象 a 的态射同构于对象 a 本身。 从范畴论的角度看,这说的是:从两个对象的余积出发的指数,同构于两个指数的积。在 Haskell 中,这个代数恒等式有一个非常实际的解释:它告诉我们,从两个类型的和出发的函数,等价于分别作用在各个类型上的一对函数。 就是函数柯里化。 返回一个对的函数,等价于一对函数,各自产生这个对中的一个元素。
(不知道为什么作者会在这里提 C-H 同构。)
Chapter 10, Natural Transformations
自然变换(Natural transformation)用于比较函子。
考虑范畴
函子还映射态射。对于态射
从逐分量的角度来看自然变换,可以说它把对象映射成了态射。而由于自然性条件的存在,也可以说它把态射映射成了可交换的正方形。
回到 Haskell,自然变换就是参数化多态函数:
-- 对于所有的类型 a,都满足
alpha :: F a -> G a同时,形如上述定义的多态函数自动满足自然性条件(得益于 Haskell 的自动类型推理,我们没必要指出 fmap 来自哪个函子定义,也没必要给出 alpha 的类型):
fmap f . alpha = alpha . fmap f以函数 safeHead 为例:
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead x::xs = Just x我们可以手动验证一下自然性条件:
-- 假设 Maybe 函子和 List 函子的 fmap 定义:
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
fmap f [] = []
fmap f (x:xs) = f x : fmap f xs
-- 那么有:
fmap f (safeHead []) = fmap f Nothing = Nothing
safeHead (fmap f []) = safeHead [] = Nothing
fmap f (safeHead (x:xs)) = fmap f (Just x) = Just (f x)
safeHead (fmap f (x:xs)) = safeHead (f x : fmap f xs) = Just (f x)直观上理解,先换容器在对容器内的东西做操作,等价于先对容器内的东西做操作再换容器。
自然变换看上去可以直观的理解成函子之间的态射。那么函子本身看上去也能构成一个范畴。对于任意一对范畴
定义一个更高层次的范畴
二范畴(2-category)是对普通范畴的推广,两个对象之间的态射可以构成范畴(而不是只在 hom 集的角度定义和讨论它们),这意味着我们可以讨论态射的态射:
| 层次 | 含义 | 在 (\mathbf{Cat}) 中的对应 |
|---|---|---|
| 对象(0-cell) | 基本对象 | 小范畴 |
| 1-态射(1-morphism) | 对象之间的态射 | 函子 |
| 2-态射(2-morphism) | 1-态射之间的态射 | 自然变换 |
我们已经定义了自然变换的复合,假设有三个函子
水平复合是指:考虑三个范畴
仍然从投影出发,选择
从二范畴的角度看,垂直复合是在态射范畴内部进行的态射复合,而水平复合则允许我们沿着 1-态射 的复合方向组合 2-态射。
Challenges
maybeToList :: Maybe a -> List a
maybeToList Nothing = []
maybeToList Just x = [x]
{--
fmap f (maybeToList Nothing)
= fmap f []
= []
maybeToList (fmap f Nothing)
= maybeToList Nothing
= []
--}-- 1st
alpha :: Reader () a -> [a]
alpha _ = []
-- 2nd
beta :: Reader () a -> [a]
beta (Reader f) = [f ()]无限多个
- 略